/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ia_psr.problemas.transportes;

/**
 *
 * @author Rubén Avalos Elvira y Fabiana Celiberti Tapie
 */
import ia_psr.datos.Horario;
import ia_psr.graph.Arista;
import ia_psr.graph.Nodo;
import ia_psr.graph.Tarea;
import ia_psr.graph.GrafoRestricciones;
import ia_psr.graph.NodoPSR;
import ia_psr.problemas.Problema;
import ia_psr.problemas.Variable;
import java.util.ArrayList;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;


public class EmpresaTransportes extends Problema {
    private PropertyChangeSupport changeSupport;
    public Horario horarioEmpresa = new Horario(8, 0, 16 ,0);
    private static EmpresaTransportes instance;

    private EmpresaTransportes() {
        // envia notificaciones cuando cambia su estado
        changeSupport      = new PropertyChangeSupport(this);
    }

    public static EmpresaTransportes getInstance() {
        if (instance == null)
            instance = new EmpresaTransportes();
        return instance;
    }

    public void setHorarioEmpresa(int hi, int mi, int hf, int mf) {
        horarioEmpresa = new Horario(hi, mi, hf, mf);
        changeSupport.firePropertyChange("et.horarioEmpresa", true, false); // se activa siempre
    }

    public Horario getHorarioEmpresa() {
        return horarioEmpresa;
    }

    public int comprobar(GrafoRestricciones g) {
        //for (Nodo n : g.nodos) {
        for (Nodo n : g.getNodos()) {
            Tarea t = (Tarea)n;
            NodoPSR n_psr = (NodoPSR)n;
            if (n_psr.valor.getValue() == null) 
                return SIN_TERMINAR;

            for (Arista a : n_psr.getAristas()) {
                NodoPSR nDestino = (NodoPSR)a.destino;
                if ( nDestino.valor.getValue() == null )
                    return SIN_TERMINAR;
                if (n_psr.valor.equals(nDestino.valor))
                    return NO_VALIDO;
            }
        }
        // Solucion teoricamente valida. Falta comprobar si es equitativa
        for (Variable v1 : elementos) {
            Conductor c1 = (Conductor)v1;

            if (tareasFueraDeHorario(c1))
                return NO_VALIDO;
            
            for (Variable v2 : elementos) {
                Conductor c2 = (Conductor)v2;
                if (c1.numTareasAsignadas() > c2.numTareasAsignadas() + 1) // medimos por numero de tareas
                    return NO_VALIDO; // una diferencia de +2 tareas implica que no es equitativo
            }
        }

        // Esta comprobacion es solo necesaria en algunos casos concretos al
        // encontrar una solucion valida. Lo hacemos aparte para optimizar los
        // tiempos de ejecucion un poco.
        for (Variable v1 : elementos) {
            Conductor c1 = (Conductor)v1;
            if (c1.tareasSuperpuestas())
                return NO_VALIDO;
        }
        return VALIDO;
    }

    public boolean tareasFueraDeHorario(Conductor c) {
        for (Tarea t : c.tareasAsignadas) {
            if (    t.h.horaInicio < horarioEmpresa.horaInicio ||
                    t.h.horaFin    > horarioEmpresa.horaFin    )
                return true;
        }
        return false;
    }

    public void resetNodo(NodoPSR n) {
        if (n instanceof Tarea) {
            Tarea t = (Tarea)n;
            Conductor c = (Conductor)t.valor;
            if (c != null)
                c.deasignarTarea(t);
        }
        n.valor = new Conductor(null);
    }

    public void resetVariables() {
        for (Variable v : elementos) {
            Conductor c = (Conductor)v;
            c.tareasAsignadas.clear();
        }
    }

    public void addConductor(Conductor c) {
        elementos.add(c);
        changeSupport.firePropertyChange("et.conductores", true, false); // se activa siempre
    }

    public void removeConductor(Conductor c) {
        elementos.remove(c);
        changeSupport.firePropertyChange("et.conductores", true, false); // se activa siempre
    }

    public void addConductores(ArrayList<Conductor> conductores) {
        for (Conductor c : conductores)
            elementos.add(c);
        changeSupport.firePropertyChange("et.conductores", true, false); // se activa siempre
    }

    public void removeAllConductores() {
        elementos.clear();
    }

    public void ordenarTareasEnConductores() {
        
    }

    // añade una clase que escuchará las notificaciones de cambio en el estado
    // interno de EmpresaTransportes.
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }

}
